//
//  DataManager.m
//  iFlickr
//
//  Created by 张 霄鹤 on 09-5-31.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "DataManager.h"

#import "MD5.h"

#import "XMLRPCRequest.h"

#import "XMLRPCResponse.h"

#import "XMLRPCConnection.h"

#import "DebugDefine.h"

#import "PhotosetInfo.h"

#import "DocumentBuilder.h"

#import "Element.h"

#import "TextNode.h"

static DataManager *dataManager = NULL;

@implementation DataManager

@synthesize token;

@synthesize perms;

@synthesize userId;

@synthesize userName;

@synthesize userFullName;

/**
 * 静态调用入口
 */
+(id) sharedDataManager{
	if(!dataManager){
		dataManager = [[DataManager alloc]  initWithApikeyAndSecret:@"32fdd35bca5b784340c0bdf523b9d3cc" secret:@"fe8a457a3077648b"];
	}
	return dataManager;
}

+(id) alloc{
	dataManager = [super alloc];
	return dataManager;
}

/**
 * 通过指定 api_key, secret 来创建 flickr账户
 */
-(id)initWithApikeyAndSecret:(NSString *)api_key secret:(NSString *)key;{
	if(self = [super init]){
		userId = @"";
		apiKey = api_key;
		secretKey = key;
		frob = @"";
		token = @"";
		// 固定的，多成分数据提交时候的分割符
		desc = @"CAFEBABE09329837ADEF";
		// 可重用的结果解析器
		fparser = [[FlickrParser alloc] init];     // TODO 此处是否需要改进
	}
	return self;
}

/**
 * 获取 frob 并且生成授权地址，用于用户授权
 */
-(NSURL *) getFrobAndAuthURL{
	NSString *method = @"nil";
	// 获取 frob
	NSString *f = [self getFrobFromServer];
	if(![f isEqualToString:@"Error"]){
		// 获取成功
		NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
		// 权限指定为 write
		[dict setObject:@"write" forKey:@"perms"];
		[dict setObject:apiKey forKey:@"api_key"];
		[dict setObject:f forKey:@"frob"];
		// 方法签名
		NSString *apisig = [self genApiSign:method params:dict];
		
		// 生成授权请求地址
		NSURL *ret = [[NSURL alloc]
					  initWithString:[NSString
					  stringWithFormat:@"http://m.flickr.com/services/auth/?api_key=%@&perms=write&frob=%@&api_sig=%@",
					  apiKey,f,apisig]];
		[dict release];
		return [ret autorelease];
	}
	return nil;
	
}

/**
 * 计算方法的签名
 * 签名方法 toHexStr(MD5(secretKeyparampairs))
 */
-(NSString *)genApiSign:(NSString *)method params:(NSDictionary *)paramDict{
	NSMutableString *ret = [NSMutableString stringWithString:secretKey];
	[paramDict setValue:apiKey forKey:@"api_key"];	
	NSArray * keys = [[paramDict keyEnumerator] allObjects];
	// 此方法会创建一个新的NSArray，但是不会拷贝原有数组的元素，只是包含引用
	NSArray *akeys = [keys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
	for(id key in akeys){
		[ret appendFormat:@"%@%@",key,[paramDict objectForKey:key]];
	}
	// 注意，keys akeys 这两个不是在这个方法中创建的，就不需要release了
	
	const char *us = [ret UTF8String];
	
	
	int len = strlen(us);
	MD5 m = MD5WithBytes(us,len);
	NSString * sret = MD5ToString(&m);
	return sret;
}

-(NSString *)getFrobFromServer{
	NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
	[data setValue:apiKey forKey:@"api_key"];
	NSString *method = @"flickr.auth.getFrob";
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
	[req setMethod:method withObject:data];
	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
	// TODO req 没有释放
	[req release];
	
	NSString *ret;
	
	id obj;
	if([resp isKindOfClass:[XMLRPCResponse class]]){	
		obj = [resp object];
		NSString *s = obj;
		NSRange rang = [s rangeOfString:@"<frob>"];
		int i1 = rang.location + rang.length;
		rang = [s rangeOfString:@"</frob>"];
		int i2 = rang.location;
		rang.location = i1;
		rang.length = i2 - i1;
		s = [s substringWithRange:rang];
		frob = [s copy];  // 此处十分重要，因为如果直接 指定 frob = s 这样，当 该方法 返回时， frob 出错
		ret = [NSString stringWithString:s];
	}else if([resp isKindOfClass:[NSError class]]){
		// NSError *err = resp;
		ret = [NSString stringWithString:@"Error"];
	}
	// [data removeAllObjects];
	[data release];
	//[resp release];
#ifdef debug
	NSLog(@"Flickr getFrobFromServer frob return %@",ret);
#endif
	return ret;
}

-(NSString *)getUserToken{
	NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
	[data setValue:apiKey forKey:@"api_key"];
	[data setValue:frob forKey:@"frob"];
	NSString *method = @"flickr.auth.getToken";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
	[req setMethod:method withObject:data];
	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
	// TODO req 没有释放
	[req release];
	
	NSString *ret = nil;
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		id obj = [resp object];
		NSString *s = obj;
#ifdef debug
		NSLog(@"token data %@",s);
#endif
		// TODO 使用 FlickrParser 进行解析
		
		BOOL bOK = [fparser parseString:s];
		
		if(bOK){
			id info = [fparser getResult];
#ifdef debug
			NSLog(@"token : %@",info);
#endif
			
			[self saveAuthInfo:info];
			
			NSDictionary *dict = (NSDictionary *)info;
			NSString *s = [dict objectForKey:@"token"];
			ret = [NSString stringWithString:s];
		}
	}else if([resp isKindOfClass:[NSError class]]){
		// NSError *err = resp;
		ret = [NSString stringWithString:@"Error"];
	}
	[data release];
	return ret;
}

-(BOOL)loadAuthInfo{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	// 此处字符串 采用 快捷方式创建，不需要释放
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:@"/userAuth.plist"];
#ifdef debug
	NSLog(@"load Auth path %@",plistPath);
#endif
	BOOL bret = NO;
	id iobj = [NSKeyedUnarchiver unarchiveObjectWithFile:plistPath];
	if(iobj){
		NSDictionary *info = (NSDictionary *)iobj;
					// TODO 给属性赋值
					self.token = [info objectForKey:@"token"];
					self.userId = [info objectForKey:@"nsid"];
					self.userName = [info objectForKey:@"username"];
					self.perms = [info objectForKey:@"perms"];
					self.userFullName = [info objectForKey:@"fullname"];
					if([self.userId length] > 0){
						bret = YES;
					}
	}
	return bret;
}

/**
 * 保存用户数据
 */
-(BOOL)saveAuthInfo:(NSDictionary *)info{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:@"/userAuth.plist"];
	BOOL bOk = [NSKeyedArchiver archiveRootObject:info toFile:plistPath];
	#ifdef debug
			if(bOk){
				NSLog(@"plist save OK");
			}else{
				NSLog(@"plist save Error");
			}
	#endif
	return bOk;
	
}

/**
 * 注销用户
 */
-(void)logout{
	userId = @"";
	userName = @"";
	token = @"";
	perms = @"";
	userFullName = @"";
	NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:userId,@"nsid"
						  ,userName,@"username"
						  ,perms,@"perms"
						  ,userFullName,@"fullname"
						  ,token,@"token"
						  ,nil,nil];
	[self saveAuthInfo:info];
	// [info release];
}

/**
 * 判断是否授权了，采用token判断
 */
-(BOOL)isAuthorized{
	return ([self.token length] > 2);
}

#pragma mark -
#pragma mark AppDocumentPath
/**
 Returns the path to the application's documents directory.
 */
- (NSString *)applicationDocumentsDirectory {
	// TODO 检查是否包含了 /
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}


#pragma mark UploadImage

/**
 * 提交图片数据到Flickr的服务器
 * @param data NSData 图像的二进制数据
 * @param params 图像标题等信息
 * @return id 
 */
-(id)uploadImageToServer:(NSData *)data withParams:(NSDictionary *)params{
	id iret = nil;
	BOOL bret = NO;
	if(data != nil){
		int len = [data length];
		if(len > 0){
			if(params != nil){
				len = [params count];
				if(len > 0){
					NSMutableDictionary *myParams = [[NSMutableDictionary alloc] initWithDictionary:params];
					id photo = [myParams objectForKey:@"photo"];
					if(photo != nil){
						[myParams removeObjectForKey:@"photo"];
					}
					NSString * title = [params objectForKey:@"title"];
					if(title == nil){
						title = @"Untitled";
						[myParams setValue:title forKey:@"title"];
					}
					[myParams setValue:apiKey forKey:@"api_key"];
					
					[myParams setValue:self.token forKey:@"auth_token"];
					
					NSString *as = [myParams objectForKey:@"api_sig"];
					if(as == nil){
						as = [self genApiSign:@"upload" params:myParams];
						[myParams setValue:as forKey:@"api_sig"];
					}
					[myParams setValue:data forKey:@"photo"];
					NSMutableURLRequest *uploadRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.flickr.com/services/upload/"]];
					[uploadRequest setHTTPMethod:@"POST"];
					[uploadRequest addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", desc] forHTTPHeaderField:@"Content-Type"];
					NSData *nData = [self convertMultipart:myParams withDesc:[NSString stringWithFormat:@"--%@",desc]];
					[uploadRequest setHTTPBody:nData];
					
					
					// TODO 继续完成，检查释放情况
					// TODO 使用NSURLConnection实现 POST方式传输
					// NSURLConnection *request = [[NSURLConnection alloc] initWithRequest:uploadRequest delegate:self];
					NSURLResponse *resp = NULL;
					NSError *err = NULL;
					NSData *ret = [NSURLConnection sendSynchronousRequest:uploadRequest returningResponse:&resp error:&err];
					
					// TODO 检查这个释放是否正常
					[uploadRequest release];
					[myParams release];
					
					if(resp){
						[resp release];
					}
					
					if(!ret){
						iret = [err autorelease];
						bret = NO;
					}else{
						// TODO 发送成功

						NSString *dd = [[NSString alloc] initWithData:ret encoding:NSUTF8StringEncoding];
#ifdef debug
						NSLog(@"%@",dd);
#endif
						// TODO 设置图像上传状态
						
						BOOL bOK = [fparser parseString:dd];
						if(bOK){
							bret = [fparser isSuccess];
							iret = [fparser getResult];
							if([iret isKindOfClass:[NSString class]]){
								bret = YES;
							}
						}						
						[dd release];
					}
				}
			}
		}
	}
	return iret;
}

/**
 * 创建 Multipart/form-data
 */
-(NSData *)convertMultipart:(NSDictionary *)params withDesc:(NSString *)de{
	if(params == nil){
		return nil;
	}
	// TODO 实现 multipart/form-data的组合
	NSMutableData *data = [[NSMutableData alloc] init];	

	char newline[2];
	newline[0] = '\n';
	newline[1] = '\n';
	NSString *cheader  = nil;
	NSData *deData = [de dataUsingEncoding:NSUTF8StringEncoding];
	for(id key in params){
		id value = [params objectForKey:key];
		if(![key isEqualToString:@"api_sig"]){
		
		[data appendData:deData]; // 添加 desc
		
		[data appendBytes:newline length:1];  // 换行
		
		cheader = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"",key]; // 设置头信息
		
		[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
		
		
			if([value isKindOfClass:[NSString class]]){
				[data appendBytes:newline length:2]; // 换两行
				// TODO 检查下面的是否正确
				cheader = [NSString stringWithFormat:@"%@",value];
				[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
				
			}else if([value isKindOfClass:[NSData class]]){
				// TODO 添加 filename
				cheader = [NSString stringWithFormat:@"; filename=\"aa.png\"\nContent-Type: application/octet-stream\n\n"];   // 使用 \n\n 实现两行
				[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
				
				[data appendData:value];
			}
			[data appendBytes:newline length:1]; // 最后换一行
		}
	}
	
	[data appendData:deData];   // 添加分割
	[data appendBytes:newline length:1];
	
	id sig = [params objectForKey:@"api_sig"];
	cheader = @"Content-Disposition: form-data; name=\"api_sig\"\n\n";		// 设置 api_sig 包含两行
	[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];

	
	NSString *sd = (NSString *)sig;
	[data appendData:[sd dataUsingEncoding:NSUTF8StringEncoding]];
	[data appendBytes:newline length:1];
	
	[data appendData:deData];
	
	[data appendData:[@"--" dataUsingEncoding:NSUTF8StringEncoding]];
	[data appendBytes:newline length:1];
	return [data autorelease];
}

/**
 * 通过用户id,图片id创建地址
 */
-(NSString *) getPhotoURL:(NSString *)nsid withID:(NSString *)photoid{
	return [NSString stringWithFormat:@"http://www.flickr.com/photos/%@/%@",nsid,photoid];
}

/**
 * 根据用户ID获取Photoset
 * @return 包含了 PhotosetInfo 的数组
 */
-(NSArray *) getPhotosetsByID:(NSString *)nsid{
	
	NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
	[data setValue:apiKey forKey:@"api_key"];
	[data setValue:nsid forKey:@"user_id"];
	NSString *method = @"flickr.photosets.getList";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
	[req setMethod:method withObject:data];
	// 此方法如果出错，那么 resp 返回的可能是 NSError
	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
	// TODO req 没有释放
	[req release];
	[data release];
	
	// TODO 处理获取结果中的数据
	
	NSMutableArray *array = [NSMutableArray array];
	
	
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		id ret = [resp object];
		NSString *xml = (NSString *)ret;
		
		// TODO 测试DOM
		
		DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
		Document *dom = [dombuilder parseWithString:xml];
		[dombuilder release];
		
		// 查询
		
		
				
		// TODO 使用 DOM 进行处理
		NSArray *ps0 = [dom getElementsByName:@"photoset"];
		if(ps0){
			array = [[[NSMutableArray alloc] init] autorelease];
			int psnum = [ps0 count];
			Element *el = nil;
			TextNode *fd = nil;
			for(int i = 0;i<psnum;i++){
				fd = nil;
				el = [ps0 objectAtIndex:i];
				PhotosetInfo *psinfo = [[[PhotosetInfo alloc] init] autorelease];
				[psinfo setProperties:([el getAttributes])];
				
				fd = (TextNode *)[dom query:[NSString stringWithFormat:@"photosets/photoset[%d]/title/#TEXT",i]];
				psinfo.title = fd.text;
				
				fd = (TextNode *)[dom query:[NSString stringWithFormat:@"photosets/photoset[%d]/description/#TEXT",i]];
				psinfo.description = fd.text;
				
				[array addObject:psinfo];
			}
		}
	}else{
		// TODO resp is NSError 访问请求出错的情况
	}	
	return array;
}

-(BOOL)addPhotoToSet:(NSString *)photoID toSet:(NSString *)setID{
	BOOL bret = NO;
	
	// 发送请求部分
	NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
	[data setValue:apiKey forKey:@"api_key"];
	[data setValue:photoID forKey:@"photo_id"];
	[data setValue:setID forKey:@"photoset_id"];
	// 必须加上token认证
	[data setValue:self.token forKey:@"auth_token"];
	
	// 对于 addPhoto 没有返回内容，如果成功，返回空内容
	NSString *method = @"flickr.photosets.addPhoto";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
	[req setMethod:method withObject:data];
	// 此方法如果出错，那么 resp 返回的可能是 NSError
	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
	// TODO req 释放
	[req release];
	[data release];
	
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		bret = ![resp isFault];
	}else{
		// TODO 出错，不需要处理，直接返回 bret就可以了
	}
	
	
	// 处理响应部分
	
	return bret;
}

-(PhotosetInfo *) createPhotoset:(NSDictionary *)params{
	id ret = nil;
	// TODO 说明，对于这种授权检查，还是放在外部去做，这种方法内部就做好请求就可以了
	NSString *title = [params objectForKey:@"title"];
	NSString *errMsg;
	BOOL bOK = NO;
	if(title){
		NSString *primary = [params objectForKey:@"primary_photo_id"];
		if(primary){
			[params setValue:self.token forKey:@"auth_token"];
			NSString *sig = [self genApiSign:@"flickr.photosets.create" params:params];
			[params setValue:sig forKey:@"api_sig"];
			XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
			[req setMethod:@"flickr.photosets.create" withObject:params];
			XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
			// TODO req 释放
			[req release];
			
			
			if([resp isKindOfClass:[XMLRPCResponse class]]){
				id result = [resp object];
				NSString *xml = (NSString *)result;
				
				DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
				Document *dom = [dombuilder parseWithString:xml];
				[dombuilder release];
				
				Element *psi = [dom query:@"photoset"];
				if(psi){
					bOK = YES;
					PhotosetInfo *pi = [[[PhotosetInfo alloc] init] autorelease];
					pi.setID = [psi getAttribute:@"id"];
					pi.url = [psi getAttribute:@"url"];
					ret = pi;
				}else{
					// TODO 出错了
					errMsg = @"parse photoset xml error";
				}
				
				//BOOL b1 = [fparser parseString:xml];
//				if(b1){
//					// TODO 请求成功
//					result = [fparser getResult];
//					if(result && [result isKindOfClass:[PhotosetInfo class]]){
//						PhotosetInfo *psi = (PhotosetInfo *)result;
//						ret = psi.setID;
//						bOK = YES;
//					}
//				}
			}else{
				// TODO 出错了
				errMsg = @"XMLRPC Request Error";
			}
			
		}else{
			// TODO 没有设定 primary
			errMsg = @"Must set primary photo";
		}
	}else{
		errMsg = @"Must set photoset title";
	}
	if(!bOK){
		NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:errMsg,NSLocalizedFailureReasonErrorKey,nil];
		ret = [NSError errorWithDomain:@"Flickr" code:-1 userInfo:info];
	}
	return ret;
}


-(void)dealloc{
	
	if(self.userId != nil){
		[self.userId release];
	}
	if(apiKey != nil){
		[apiKey release];
	}
	if(secretKey != nil){
		[secretKey release];
	}
	if(frob != nil){
		[frob release];
	}
	if(self.token != nil){
		[self.token release];
	}
	if(self.perms != nil){
		[self.perms release];
	}
	if(self.userName != nil){
		[self.userName release];
	}
	if(self.userFullName != nil){
		[self.userFullName release];
	}
	if(desc != nil){
		[desc release];
	}
	if(fparser != nil){
		[fparser release];
	}
	[super dealloc];
}

@end
